package design_patterns_and_best_practices_in_java;

import io.reactivex.Observable;
import io.reactivex.schedulers.Schedulers;

import java.time.LocalDateTime;
import java.util.concurrent.TimeUnit;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.Supplier;
import java.util.stream.Collectors;
import java.util.stream.IntStream;
import java.util.stream.Stream;

enum Singleton {
    INSTANCE;

    public static Supplier<Singleton> getInstance() {
        return () -> Singleton.INSTANCE;
    }

    public void doSomething() {
        System.out.println("Something is done");
    }
}

/**
 * Created with IntelliJ IDEA.
 * Description:
 *
 * @author lzy
 * @create 2019-11-15 上午11:03
 */
public class Chapter5Functional {
    public static void main(String[] args) {
        Function<Integer, Function<Integer, Integer>> square_radius = x -> y -> x * x + y * y;
        Integer a = 100;
        Integer finalA = a;
        Function<Integer, Integer> add100 = b -> b + finalA;
        System.out.println(add100.apply(9));
        a = 101;
        System.out.println(add100.apply(9));

        IntStream.iterate(1, x -> x + 1).peek(System.out::println).iterator();

        Singleton.getInstance().get().doSomething();

        Function<String, String> toHex =
                x -> x.chars().boxed().map(y -> "0x" + Integer.toHexString(y)).collect(Collectors.joining(" "));
        Consumer<String> toAscii = x -> System.out.println("Print ASCII: " + x);
        Consumer<String> decorateToHex = x -> System.out.println("Print Hex: " + toHex.apply(x));
        toAscii.andThen(decorateToHex).accept("text");

        System.out.println(Stream.<Function<String, String>>of(String::toLowerCase,
                x -> LocalDateTime.now().toString() + " " + x).map(f -> f.apply("text")).collect(Collectors.toList()));

        Observable.range(1, 5).map(z -> (z + 10) / (z - 5))
                .retryWhen(e -> e.zipWith(Observable.range(1, 2), (y, z) -> z).flatMap(r -> Observable.timer(500 * r,
                        TimeUnit.SECONDS))).subscribe(System.out::println);

        Observable.range(1, 2).map(x -> {
            System.out.println("[Map]Thread " + Thread.currentThread().getName());
            return x + 10;
        }).subscribeOn(Schedulers.computation()).subscribe(y -> System.out.println("[Subscribe]Thread " + Thread.currentThread().getName() + " - " + y));



    }
}